package fgin

import (
	"context"
	"crypto/tls"
	"errors"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"

	"github.com/gin-gonic/gin"
	"google.golang.org/grpc"
	"google.golang.org/grpc/health"
	healthpb "google.golang.org/grpc/health/grpc_health_v1"
)

func (f *Fgin) GetHttpGrpcServer(path string) (*gin.Engine, *grpc.Server) {
	// 读取配置
	readConfig(path)
	// 判断定义的协议
	if fginConfig.NetType != "http_grpc" {
		panic(fmt.Sprintf("您配置的net_type:%v,本方法适用的协议为:http_grpc", fginConfig.NetType))
	}
	// 服务名必填
	if fginConfig.ServiceName == "" {
		panic("grpc服务,service_name必填")
	}
	// tag必填
	if fginConfig.Tag == "" {
		panic("grpc服务,tag必填")
	}
	// 进行router初始化
	var router *gin.Engine
	switch fginConfig.Env {
	case "pro":
		// 生产模式
		gin.SetMode(gin.ReleaseMode)
		router = gin.New()
	case "dev":
		// 调试模式
		gin.SetMode(gin.DebugMode)
		router = gin.New()
	default:
		panic(errors.New("env配置错误,只支持:pro生产模式,dev调试模式"))
	}
	// 初始化日志
	logInit()
	// 启动通用组件
	startHttpGrpcPlug()
	// http增加中间件
	addMiddleWare(router)
	// http自定义组件
	PlugsHttpStart(router)
	// grpc自定义组件
	PlugsGrpcStart()
	// http探针
	if !fginConfig.DisablePing {
		router.GET("/ping", func(ctx *gin.Context) {
			ReturnJson(ctx, 200, "pong", nil)
		})
	}

	// 创建grpc服务
	s := newGrpcServer()
	// 实现默认的健康检查
	healthServer := health.NewServer()
	healthServer.SetServingStatus("", healthpb.HealthCheckResponse_SERVING)
	healthpb.RegisterHealthServer(s, healthServer)
	return router, s
}

// 初始化组件
func startHttpGrpcPlug() {
	// opentelemetry 初始化
	initOpentelemetry()
	var wg sync.WaitGroup
	// 1. 初始化mysql gorm
	wg.Add(1)
	go func() {
		defer wg.Done()
		initGorm()
	}()
	// 2. 初始化redis
	wg.Add(1)
	go func() {
		defer wg.Done()
		initRedis()
	}()
	// 3. grpc客户端
	wg.Add(1)
	go func() {
		defer wg.Done()
		initGrpcClientV2()
	}()
	// 4. rabbitmq队列初始化
	wg.Add(1)
	go func() {
		defer wg.Done()
		initRabbitmq()
	}()
	// 5. jaeger初始化
	wg.Add(1)
	go func() {
		defer wg.Done()
		initJaeger()
	}()
	// 6. prometheus初始化
	wg.Add(1)
	go func() {
		defer wg.Done()
		initPrometheus()
	}()
	// 7. 神盾启动
	wg.Add(1)
	go func() {
		defer wg.Done()
		initAegis()
	}()
	// 9. 注册到consul,如果有配置
	wg.Add(1)
	go func() {
		defer wg.Done()
		initConsul()
	}()
	// 10. 独立校验器
	wg.Add(1)
	go func() {
		defer wg.Done()
		initValidator()
	}()
	wg.Wait()
}

// 同时启动http grpc
func (f *Fgin) RunHttpGrpc(r *gin.Engine, s *grpc.Server) {
	var wg sync.WaitGroup
	wg.Add(2)
	go httpRun(r, &wg)
	go grpcRun(s, &wg)
	wg.Wait()
}

// 同时启动httpTLS grpc
func (f *Fgin) RunHttpTLSGrpc(r *gin.Engine, s *grpc.Server, certFile, keyFile, tlsMinVersion string) {
	var wg sync.WaitGroup
	wg.Add(2)
	go httpTLSRun(r, &wg, certFile, keyFile, tlsMinVersion)
	go grpcRun(s, &wg)
	wg.Wait()
}

// http启动
func httpRun(router *gin.Engine, wg *sync.WaitGroup) {
	defer wg.Done()
	if fginConfig.Ip == "" {
		logSuger.Warn("ip没有配置,使用默认ip:127.0.0.1")
		fginConfig.Ip = "127.0.0.1"
	}
	if fginConfig.HttpPort == 0 {
		logSuger.Warn("http_port没有配置,使用默认port:8080")
		fginConfig.HttpPort = 8080
	}
	srv := &http.Server{
		Addr:    fmt.Sprintf("%s:%v", fginConfig.Ip, fginConfig.HttpPort),
		Handler: router,
	}

	go func() {
		// 服务连接
		logSuger.Info(fmt.Sprintf("http服务启动: %s:%v", fginConfig.Ip, fginConfig.HttpPort))
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("listen: %v\n", err)
		}
	}()

	// 等待中断信号以优雅地关闭服务器（设置 5 秒的超时时间）
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
	<-quit
	logSuger.Info("Http Shutdown Server ...")

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	defer rabbitmqClose()
	if err := srv.Shutdown(ctx); err != nil {
		log.Fatalf("Http Server Shutdown:%v", err)
	}
	logSuger.Info("Http Server exiting")
}

// httpTLS启动
func httpTLSRun(router *gin.Engine, wg *sync.WaitGroup, certFile, keyFile, tlsMinVersion string) {
	defer wg.Done()
	if fginConfig.Ip == "" {
		logSuger.Warn("ip没有配置,使用默认ip:127.0.0.1")
		fginConfig.Ip = "127.0.0.1"
	}
	if fginConfig.HttpPort == 0 {
		logSuger.Warn("http_port没有配置,使用默认port:8080")
		fginConfig.HttpPort = 8080
	}
	// tls 版本 默认最低是1.2
	tlsConfig := &tls.Config{}
	switch tlsMinVersion {
	case "1.0":
		tlsConfig.MinVersion = tls.VersionTLS10
		logSuger.Info("tls最低支持版本1.0")
	case "1.1":
		tlsConfig.MinVersion = tls.VersionTLS11
		logSuger.Info("tls最低支持版本1.1")
	case "1.2":
		tlsConfig.MinVersion = tls.VersionTLS12
		logSuger.Info("tls最低支持版本1.2")
	case "1.3":
		tlsConfig.MinVersion = tls.VersionTLS13
		logSuger.Info("tls最低支持版本1.3")
	default:
		logSuger.Info("使用tls默认最低支持版本")
	}
	srv := &http.Server{
		Addr:      fmt.Sprintf("%s:%v", fginConfig.Ip, fginConfig.HttpPort),
		Handler:   router,
		TLSConfig: tlsConfig,
	}

	go func() {
		// 服务连接
		logSuger.Info(fmt.Sprintf("https服务启动: %s:%v", fginConfig.Ip, fginConfig.HttpPort))
		if err := srv.ListenAndServeTLS(certFile, keyFile); err != nil && err != http.ErrServerClosed {
			log.Fatalf("listen: %v\n", err)
		}
	}()

	// 等待中断信号以优雅地关闭服务器（设置 5 秒的超时时间）
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
	<-quit
	logSuger.Info("Https Shutdown Server ...")

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	defer rabbitmqClose()
	if err := srv.Shutdown(ctx); err != nil {
		log.Fatalf("Https Server Shutdown:%v", err)
	}
	logSuger.Info("Https Server exiting")
}

// grpc启动
func grpcRun(s *grpc.Server, wg *sync.WaitGroup) {
	defer wg.Done()
	if fginConfig.Ip == "" {
		logSuger.Warn("ip没有配置,使用默认ip:127.0.0.1")
		fginConfig.Ip = "127.0.0.1"
	}
	if fginConfig.GrpcPort == 0 {
		logSuger.Warn("port没有配置,使用默认port:8081")
		fginConfig.GrpcPort = 8081
	}
	address := fmt.Sprintf("%v:%v", fginConfig.Ip, fginConfig.GrpcPort)
	listen, err := net.Listen("tcp", address)
	if err != nil {
		panic(err.Error())
	}
	defer listen.Close()
	defer rabbitmqClose()
	go func() {
		logSuger.Info(fmt.Sprintf("grpc服务%v启动成功:%v", fginConfig.ServiceName, address))
		if err := s.Serve(listen); err != nil {
			log.Fatalf("listen: %v\n", err)
		}
	}()
	// 优雅停止grpc服务
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
	<-quit
	deregisterService() // 存在consul注销服务
	logSuger.Info("Grpc Shutdown Server ...")
	s.GracefulStop()
	logSuger.Info("Grpc Server exiting")
}
